package fr.afcepf.atod18.hotels.managedbeans;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import javax.annotation.Resource;
import javax.faces.bean.SessionScoped;

import org.apache.cxf.jaxrs.client.JAXRSClientFactory;
import org.codehaus.jackson.jaxrs.JacksonJsonProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;

import fr.afcepf.atod18.hotels.entities.Chambre;
import fr.afcepf.atod18.hotels.entities.IReservation;
import fr.afcepf.atod18.hotels.entities.Reservationchambre;
import fr.afcepf.atod18.hotels.entities.ReservationchambreId;
import fr.afcepf.atod18.hotels.entities.Reservationoption;
import fr.afcepf.atod18.hotels.entities.ReservationoptionId;
import fr.afcepf.atod18.hotels.entities.Selections;
import fr.afcepf.atod18.hotels.entities.Tarif;
import fr.afcepf.atod18.hotels.entities.Utilisateur;
import fr.afcepf.atod18.hotels.services.interfaces.IServiceHotel;
import fr.afcepf.atod18.hotels.services.interfaces.IServiceOption;
import fr.afcepf.atod18.hotels.services.interfaces.IServiceSelections;
import fr.afcepf.atod18.hotels.services.interfaces.IServiceUtilisateur;
import fr.afcepf.atod18.hotels.utilitaires.Item;
import fr.afcepf.atod18.hotels.webservices.ChangeDTO;
import fr.afcepf.atod18.hotels.webservices.CurrencyDTO;
import fr.afcepf.atod18.hotels.webservices.IServiceChangeWithFee;

@SessionScoped
@Controller
@Transactional
public class BasketManagedBean {
	@Autowired
	private IServiceUtilisateur serviceUtilisateur;
	@Autowired
	private IServiceSelections servicePanier;
	@Autowired
	private IServiceHotel serviceHotel;
	@Autowired
	private IServiceOption serviceOption;
	@Resource
	private LoginManagedBean login;
	@Resource
	private SearchEngineManagedBean search;

	// interface for calling RESTful WebService, null by default
	IServiceChangeWithFee scf = null;
	
	// used to display list of avalaible currencies
	private String selectedCurrency = "EURO"; 
	private List<CurrencyDTO> currencies = null;
	private ChangeDTO changeDTO = new ChangeDTO(0, 0);
	private String changeResult="";
	
	// used by basket.jsf for displaying History of Closed (Paid) Basket
	private List<UI_BasketSelection> listDesSelections = new ArrayList<UI_BasketSelection>();

	// used by finalizeReservation.jsf for displaying active basket
	// always contains only one Selections:
	// - retrieve from database for current user
	// - or create from booking process
	private List<UI_BasketSelection> currentSelections = new ArrayList<UI_BasketSelection>();

	// Date to String converter
	private SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");

	Selections sel = null;

	private String buyStringButton = "Payer";
	/*
	 * called by finalizeReservation.jsf finalize booking process for the user
	 * and show the active cart (basket). If connected, proceed with reservation
	 * process or payment process otherwise, continue with new client recording
	 * process.
	 */
    public void finalizeReservation() {
		System.out.println("finalizeReservation: Start");
		/*
		 * get all data from managed bean SearchengineManagedBean to finalize
		 * those room booking with options
		 */
		currentSelections.clear();

		if (search == null)
			System.out
					.println("finalizeReservation: Alarm SearchEngineManagedBean instance is NULL !!!");
		if (login == null)
			System.out
					.println("finalizeReservation: Alarm SearchEngineManagedBean instance is NULL !!!");

		sel = new Selections();
		sel.setIdSelections(0);
		sel.setLastModificationDate(Calendar.getInstance().getTime());
		sel.setPaye((byte) 0);
		if (login.getConnectedUser() != null)
			sel.setUtilisateurIdUser(login.getConnectedUser().getIdUser());
		else
			sel.setUtilisateurIdUser(0);

		for (Chambre ch : search.getChambresEnReservation()) {
			System.out.println("finalizeReservation: build ReservationChambre");

			Reservationchambre rc = new Reservationchambre();
			ReservationchambreId rci = new ReservationchambreId();
			rc.setId(rci);

			rci.setSelectionsidSelections(0);
			rci.setChambreidHotel(search.getSelectedHotel());
			rci.setChambreNumero(ch.getId().getNumero());
			rci.setDateDebut(search.getDateDepart());
			rci.setDateFin(search.getDateArrive());
			Tarif t = serviceHotel.getTarifChambre(rc.getId()
					.getChambreidHotel(), rc.getId().getChambreNumero());
			System.out.println("finalizeReservation: retrieve Tarif for" + rci);
			rc.setPrice(t.getPrix());
			rc.setReservation(null);

			System.out
					.println("finalizeReservation: retrieve SelectedOption data for ReservationChambre "
							+ search.getChambresEnReservation().indexOf(ch));
			// get list of Options for this booking
			List<Item> listOfOptions = null;
			switch (search.getChambresEnReservation().indexOf(ch)) {
			case 0:
				listOfOptions = search.getItemsChambre1();
				break;
			case 1:
				listOfOptions = search.getItemsChambre2();
				break;
			case 2:
				listOfOptions = search.getItemsChambre3();
				break;
			}
			// treat the list of options
			for (Item it : listOfOptions)
				if (it.getSelectedQuantite() > 0) {
					System.out
							.println("finalizeReservation: build ReservationOption");
					Reservationoption ro = new Reservationoption();
					ReservationoptionId roi = new ReservationoptionId();
					ro.setId(roi);

					ro.getId()
							.setChambreidHotel(rc.getId().getChambreidHotel());
					ro.getId().setChambreNumero(rc.getId().getChambreNumero());
					ro.getId().setDateDebut(rc.getId().getDateDebut());
					ro.getId().setDateFin(rc.getId().getDateFin());
					ro.getId().setSelectionsidSelections(0);
					ro.getId().setOptionidOption(it.getIdOption());
					ro.setQuantite(it.getSelectedQuantite());
					ro.setPrice(serviceOption.getPrix(it.getIdOption()));
					System.out
							.println("finalizeReservation: find queue of ReservationOption");
					// add ReservationOption to the tail of IReservation queue
					IReservation tail = rc;
					while (tail.getReservation() != null)
						tail = tail.getReservation();
					System.out
							.println("finalizeReservation: queue ReservationOption");
					tail.setReservation(ro);
				}
			System.out.println("finalizeReservation: queue ReservationChambre");
			// add ReservationChambre to Selections
			sel.getReservations().add(rc);
		}

		// now, active selection is ready to save to database
		// but need to be validate by user
		// prepare display of active selection
		System.out.println("finalizeReservation: prepare Selection for UI");
		currentSelections.add(prepareSelectionsForUI(sel));
		
        System.out.println("finalizeReservation: call WebService RESTful WSCoordination");
        CreateIServiceChangeWithFee();
        currencies = scf.getCurrenciesList().getListCurrency();
        changeDTO = new ChangeDTO(currentSelections.get(0).getTotal(), 0);
        onCurrencySelect();
		System.out.println("finalizeReservation: End");
        if (login.getConnectedUser() != null) {
            setBuyStringButton("Finaliser la transaction");
        }
        else {
            setBuyStringButton("S'authentifier pour payer");
        }
            
	}
    
    @SuppressWarnings("unchecked")
    private void CreateIServiceChangeWithFee()
    {
        /*
         *  call Restful WebService to obtain currencies to display
         *     Create a Jackson JSON provider to unmarshall JSON data from body
         *     providers list is not typed, type it to Object ? to test further...
         *     Pass the provider list to JAXRSClientFactory. If you dont pass providers list,
         *     typed list in JSON connot be unmarshall :) Thool
         */
      if (scf == null ) {
        @SuppressWarnings("rawtypes")
          List providers = new ArrayList();
        providers.add( new JacksonJsonProvider());
        scf = JAXRSClientFactory.create("http://localhost:8080/WsCoordination/services", IServiceChangeWithFee.class, providers);
      }
    }
    
    public void onCurrencySelect() {
        CreateIServiceChangeWithFee();
        if (selectedCurrency.contentEquals("EURO")) {
            changeResult =  String.format("%.2f %s", changeDTO.getConverted_amount(), selectedCurrency);
            
        }
        else {
          changeDTO = scf.getChangeWithFee( currentSelections.get(0).getTotal(), "EURO", selectedCurrency );
          changeResult = String.format("%.2f %s  +  %.2f commission  =  %.2f %s",
                  changeDTO.getConverted_amount(), selectedCurrency, changeDTO.getFee(),
                  (changeDTO.getConverted_amount()+changeDTO.getFee()), selectedCurrency);
        }
    }
    
	protected UI_BasketSelection prepareSelectionsForUI(Selections s) {
		// for each selection in selections
		// create a new UI_BasketSelection and fill it with its
		// reservations

		UI_BasketSelection ui_sel = new UI_BasketSelection();
		ui_sel.dateModification = sdf.format(s.getLastModificationDate());
		ui_sel.selectionID = Integer.toString(s.getIdSelections());

		for (IReservation resa : s.getReservations()) {
			// for each reservation chambre inside this selection
			// create a new UI_BasketReservation

			UI_BasketReservation ui_resa = new UI_BasketReservation();
			ui_resa.setCh((Reservationchambre) resa);
			ui_resa.setHotelname(serviceHotel.getHotelByID(
					ui_resa.getCh().getId().getChambreidHotel()).getName());
			double price = ui_resa.getCh().getPrice();
			IReservation next = ui_resa.getCh().getReservation();
			while (next != null) {
				UI_BasketOption bo = new UI_BasketOption();
				bo.setOptionId(((Reservationoption) next).getId()
						.getOptionidOption());
				bo.setPrice(((Reservationoption) next).getPrice());
				bo.setQte(((Reservationoption) next).getQuantite());
				bo.setOption_name(servicePanier.getOptionName(bo.getOptionId()));
				ui_resa.getListOptions().add(bo);
				System.out
						.println("BasketManagedBean: initialize: create UI for option "
								+ ((Reservationoption) next));
				next = next.getReservation();
			} // end of foreach ReservationOption

			ui_resa.setPrice(price);
			// add the UI_BasketReservation to UI_BasketSelection
			ui_sel.reservations.add(ui_resa);
			System.out
					.println("BasketManagedBean: initialize: create UI for resa "
							+ resa);
		} // end of foreach ReservationChambre

		return ui_sel;
	}

	/*
	 * called to initialize data for displaying History of Closed (paid)
	 * Selections
	 */
	public void initialize() {
		System.out.println("BasketManagedBean: initialize start");
		// load data for current connected userconnected or not
		listDesSelections.clear();
		System.out.println("BasketManagedBean: initialize: login " + login);
		if (login != null) {
			Utilisateur user = login.getConnectedUser();
			System.out.println("BasketManagedBean: initialize: login user"
					+ user);
			if (user != null) {
				int userId = user.getIdUser();
				// get history of selections for UserID
				List<Selections> selections = servicePanier
						.getHistoryOfSelectionsByUserId(userId);
				System.out
						.println("BasketManagedBean: initialize: user's selections count "
								+ selections.size());

				for (Selections s : selections) {
					// add the UI_BasketSelection to the List of
					// UI_BasketSelection
					listDesSelections.add(prepareSelectionsForUI(s));
					System.out
							.println("BasketManagedBean: initialize: create UI for selection "
									+ s);
				} // end of foreach selection for this user

			} // end of if user exists

		} // end of if login exists
		System.out.println("BasketManagedBean: initialize end");
	}

	public String cancelBasket() {
		currentSelections.clear();
		return "welcome.jsf";
	}

	public String buyBasket() {
		sel.setPaye((byte) 1);
		if (login.getConnectedUser() == null) {
			return "avantCreationCompte.jsf";
		}
		saveBasket();
		return "monProfil.jsf";
	}

	public void saveBasket() {
		if (login.getConnectedUser() != null) {
			List<Selections> panier = new ArrayList<Selections>();
			if (currentSelections.size() > 0) {
				sel.setUtilisateurIdUser(login.getConnectedUser().getIdUser());
				panier.add(sel);
				servicePanier.saveSelections(panier);
				currentSelections.clear();
			}
		}
	}

	public String bookBasket() {
		sel.setPaye((byte) 0);
		if (login.getConnectedUser() == null)
			return "avantCreationCompte.jsf";
		saveBasket();
		return "welcome.jsf";
	}

	public IServiceUtilisateur getServiceUtilisateur() {
		return serviceUtilisateur;
	}

	public void setServiceUtilisateur(IServiceUtilisateur serviceUtilisateur) {
		this.serviceUtilisateur = serviceUtilisateur;
	}

	public LoginManagedBean getLogin() {
		return login;
	}

	public void setLogin(LoginManagedBean login) {
		this.login = login;
	}

	public IServiceSelections getServicePanier() {
		return servicePanier;
	}

	public void setServicePanier(IServiceSelections servicePanier) {
		this.servicePanier = servicePanier;
	}

	public IServiceHotel getServiceHotel() {
		return serviceHotel;
	}

	public void setServiceHotel(IServiceHotel serviceHotel) {
		this.serviceHotel = serviceHotel;
	}

	public List<UI_BasketSelection> getListDesSelections() {
		// call initialize() to retrive History of Selections for connected user
		initialize();
		return listDesSelections;
	}

	public void setListDesSelections(List<UI_BasketSelection> listDesSelections) {
		this.listDesSelections = listDesSelections;
	}

	public IServiceOption getServiceOption() {
		return serviceOption;
	}

	public void setServiceOption(IServiceOption serviceOption) {
		this.serviceOption = serviceOption;
	}

	public SearchEngineManagedBean getSearch() {
		return search;
	}

	public void setSearch(SearchEngineManagedBean search) {
		this.search = search;
	}

	public List<UI_BasketSelection> getCurrentSelections() {
		// build and display active basket from booking process
		System.out.println("getCurrentSelections: begin");
		finalizeReservation();
		System.out.println("getCurrentSelections: end");
		return currentSelections;
	}

	public void setCurrentSelections(List<UI_BasketSelection> currentSelections) {
		this.currentSelections = currentSelections;
	}

    /**
     * @return the currencies
     */
    public List<CurrencyDTO> getCurrencies() {
        return currencies;
    }

    /**
     * @param paramCurrencies the currencies to set
     */
    public void setCurrencies(List<CurrencyDTO> paramCurrencies) {
        currencies = paramCurrencies;
    }

    public String getSelectedCurrency() {
        return selectedCurrency;
    }

    public void setSelectedCurrency(String paramSelectedCurrency) {
        selectedCurrency = paramSelectedCurrency;
    }

    public ChangeDTO getChangeDTO() {
        return changeDTO;
    }

    public void setChangeDTO(ChangeDTO paramChangeDTO) {
        changeDTO = paramChangeDTO;
    }

    public String getChangeResult() {
        return changeResult;
    }

    public void setChangeResult(String paramChangeResult) {
        changeResult = paramChangeResult;
    }

    public String getBuyStringButton() {
        return buyStringButton;
    }

    public void setBuyStringButton(String paramBuyStringButton) {
        buyStringButton = paramBuyStringButton;
    }

}
